package com.hope.hotel.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.hope.hotel.entity.po.Booking;
import com.hope.hotel.entity.vo.RoomTypeStatsVO;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * 预订Mapper接口
 * </p>
 *
 * @author author
 * @since 2025-05-30
 */
@Mapper
public interface BookingMapper extends BaseMapper<Booking> {



    /**
     * 获取指定日期范围内每天的房间可用情况
     * 
     * @param roomId 房间ID
     * @param startDate 开始日期
     * @param endDate 结束日期
     * @return 每天的房间可用情况列表
     */
    List<Map<String, Object>> getRoomAvailabilityByDateRange(
        @Param("roomId") Long roomId,
        @Param("startDate") LocalDate startDate,
        @Param("endDate") LocalDate endDate
    );
    
    /**
     * 获取指定时间段内最大可预订房间数量
     * 通过计算每一天的可用房间数，取最小值作为整个时间段的最大可预订数量
     * 
     * @param roomId 房间ID
     * @param checkIn 入住时间
     * @param checkOut 退房时间
     * @return 最大可预订房间数量
     */
    Integer getMaxAvailableRooms(
        @Param("roomId") Long roomId,
        @Param("checkIn") LocalDateTime checkIn,
        @Param("checkOut") LocalDateTime checkOut
    );

    /**
     * 更新订单状态
     */
    @Update("update booking set pay_status = 1 where booking_id = #{bookingId}")
    void updateBookingStatus(String bookingId);
    
    /**
     * 更新订单支付状态
     * 
     * @param bookingId 订单ID
     * @param payStatus 支付状态(0:未支付,1:已支付)
     * @return 影响行数
     */
    @Update("update booking set pay_status = #{payStatus}, updated_at = now() where booking_id = #{bookingId}")
    int updatePayStatus(@Param("bookingId") String bookingId, @Param("payStatus") Integer payStatus);
    
    /**
     * 获取酒店订单列表(分页)
     * 
     * @param page 分页对象
     * @param hotelId 酒店ID
     * @param keyword 关键词(订单号或客户名)
     * @param status 订单状态
     * @param startDate 开始日期
     * @param endDate 结束日期
     * @return 分页结果
     */
    @Select({
        "<script>",
        "SELECT b.booking_id, b.order_no, b.user_id, b.hotel_id, b.room_id, ",
        "b.check_in, b.check_out, b.guest_count, b.total_price, b.status, ",
        "b.pay_status, b.created_at, b.updated_at, ",
        "u.username as customer_name, u.phone, ",
        "r.name as room_type, r.room_numbers ",
        "FROM booking b ",
        "LEFT JOIN users u ON b.user_id = u.user_id ",
        "LEFT JOIN rooms r ON b.room_id = r.id ",
        "WHERE b.hotel_id = #{hotelId} ",
        "<if test='keyword != null and keyword != \"\"'>",
        "AND (b.order_no LIKE CONCAT('%', #{keyword}, '%') OR u.username LIKE CONCAT('%', #{keyword}, '%')) ",
        "</if>",
        "<if test='status != null and status != \"\"'>",
        "AND b.status = #{status} ",
        "</if>",
        "<if test='startDate != null and startDate != \"\"'>",
        "AND DATE(b.check_in) &gt;= #{startDate} ",
        "</if>",
        "<if test='endDate != null and endDate != \"\"'>",
        "AND DATE(b.check_in) &lt;= #{endDate} ",
        "</if>",
        "ORDER BY b.created_at DESC",
        "</script>"
    })
    Page<Map<String, Object>> searchHotelBookings(
        Page<Map<String, Object>> page,
        @Param("hotelId") String hotelId,
        @Param("keyword") String keyword,
        @Param("status") String status,
        @Param("startDate") String startDate,
        @Param("endDate") String endDate
    );
    
    /**
     * 获取订单详情(管理员视角)
     * 
     * @param bookingId 订单ID
     * @return 订单详情
     */
    @Select({
        "SELECT b.booking_id, b.order_no, b.user_id, b.hotel_id, b.room_id, ",
        "b.check_in, b.check_out, b.guest_count, b.quantity, b.total_price, ",
        "b.status, b.pay_status, b.remark, b.created_at, b.updated_at, ",
        "u.username as customer_name, u.phone, ",
        "r.name as room_type, r.room_numbers, h.name as hotel_name ",
        "FROM booking b ",
        "LEFT JOIN users u ON b.user_id = u.user_id ",
        "LEFT JOIN rooms r ON b.room_id = r.id ",
        "LEFT JOIN hotels h ON b.hotel_id = h.hotel_id ",
        "WHERE b.booking_id = #{bookingId}"
    })
    Map<String, Object> getBookingDetailForAdmin(@Param("bookingId") String bookingId);
    
    /**
     * 获取订单的入住人信息
     * 
     * @param bookingId 订单ID
     * @return 入住人列表
     */
    @Select({
        "SELECT bt.id, bt.name, bt.id_card ",
        "FROM booking_traveler bt ",
        "WHERE bt.booking_id = #{bookingId}"
    })
    List<Map<String, Object>> getBookingTravelers(@Param("bookingId") String bookingId);
    
    /**
     * 检查酒店管理员权限
     * 
     * @param hotelId 酒店ID
     * @param adminId 管理员ID
     * @return 记录数(大于0表示有权限)
     */
    @Select({
        "SELECT COUNT(*) FROM hotels h ",
        "WHERE h.hotel_id = #{hotelId} AND h.admin_id = #{adminId}"
    })
    Integer checkHotelAdminPermission(
        @Param("hotelId") String hotelId,
        @Param("adminId") String adminId
    );
    
    /**
     * 统计酒店的所有订单数量
     * 
     * @param hotelId 酒店ID
     * @return 订单总数
     */
    Integer countBookingsByHotel(@Param("hotelId") Long hotelId);
    
    /**
     * 统计酒店特定状态的订单数量
     * 
     * @param hotelId 酒店ID
     * @param status 订单状态
     * @param payStatus 支付状态(可为null，表示不筛选支付状态)
     * @return 符合条件的订单数量
     */
    Integer countBookingsByStatus(
        @Param("hotelId") Long hotelId,
        @Param("status") String status,
        @Param("payStatus") Integer payStatus
    );
    
    /**
     * 获取按月统计的订单数据
     * 
     * @param hotelId 酒店ID
     * @param startDate 开始日期
     * @param endDate 结束日期
     * @return 月度订单统计数据
     */
    List<Map<String, Object>> getMonthlyOrderStats(
        @Param("hotelId") Long hotelId,
        @Param("startDate") LocalDate startDate,
        @Param("endDate") LocalDate endDate
    );
    
    /**
     * 获取按季度统计的订单数据
     * 
     * @param hotelId 酒店ID
     * @param startDate 开始日期
     * @param endDate 结束日期
     * @return 季度订单统计数据
     */
    List<Map<String, Object>> getQuarterlyOrderStats(
        @Param("hotelId") Long hotelId,
        @Param("startDate") LocalDate startDate,
        @Param("endDate") LocalDate endDate
    );
    
    /**
     * 获取按年统计的订单数据
     * 
     * @param hotelId 酒店ID
     * @param startDate 开始日期
     * @param endDate 结束日期
     * @return 年度订单统计数据
     */
    List<Map<String, Object>> getYearlyOrderStats(
        @Param("hotelId") Long hotelId,
        @Param("startDate") LocalDate startDate,
        @Param("endDate") LocalDate endDate
    );
    
    /**
     * 获取房型订单分布统计
     * 
     * @param hotelId 酒店ID
     * @return 房型订单分布统计数据
     */
    List<RoomTypeStatsVO> getRoomTypeBookingStats(@Param("hotelId") Long hotelId);

    /**
     * 获取月度订单数量统计
     */
    List<Integer> getMonthlyOrderCounts(
        @Param("hotelId") Long hotelId, 
        @Param("startDate") LocalDate startDate, 
        @Param("endDate") LocalDate endDate
    );
    
    /**
     * 获取月度收入统计
     */
    List<BigDecimal> getMonthlyRevenue(
        @Param("hotelId") Long hotelId, 
        @Param("startDate") LocalDate startDate, 
        @Param("endDate") LocalDate endDate
    );
    
    /**
     * 获取季度订单数量统计
     */
    List<Integer> getQuarterlyOrderCounts(
        @Param("hotelId") Long hotelId, 
        @Param("startDate") LocalDate startDate, 
        @Param("endDate") LocalDate endDate
    );
    
    /**
     * 获取季度收入统计
     */
    List<BigDecimal> getQuarterlyRevenue(
        @Param("hotelId") Long hotelId, 
        @Param("startDate") LocalDate startDate, 
        @Param("endDate") LocalDate endDate
    );
    
    /**
     * 获取年度订单数量统计
     */
    List<Integer> getYearlyOrderCounts(
        @Param("hotelId") Long hotelId, 
        @Param("startDate") LocalDate startDate, 
        @Param("endDate") LocalDate endDate
    );
    
    /**
     * 获取年度收入统计
     */
    List<BigDecimal> getYearlyRevenue(
        @Param("hotelId") Long hotelId, 
        @Param("startDate") LocalDate startDate, 
        @Param("endDate") LocalDate endDate
    );
}